package com.sevenluo.netty.learn.server;

import com.sevenluo.netty.learn.server.codec.OrderFrameDecoder;
import com.sevenluo.netty.learn.server.codec.OrderFrameEncoder;
import com.sevenluo.netty.learn.server.codec.OrderProtocolDecoder;
import com.sevenluo.netty.learn.server.codec.OrderProtocolEncoder;
import com.sevenluo.netty.learn.server.codec.handler.AuthHandler;
import com.sevenluo.netty.learn.server.codec.handler.MetricHandler;
import com.sevenluo.netty.learn.server.codec.handler.OrderServerProcessHandler;
import com.sevenluo.netty.learn.server.codec.handler.ServerIdleCheckHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import io.netty.handler.ipfilter.RuleBasedIpFilter;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;

import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;

/**
 * 服务器端实现
 * @author sevenluo
 */
public class Server {

    public static void main(String[] args) throws InterruptedException, ExecutionException, CertificateException, SSLException {


        NioEventLoopGroup boss = new NioEventLoopGroup(0, new DefaultThreadFactory("boss"));
        NioEventLoopGroup worker = new NioEventLoopGroup(0, new DefaultThreadFactory("worker"));

        final MetricHandler metricHandler = new MetricHandler();

        // 使用 netty 提供的线程池
        EventExecutorGroup eventExecutors = new UnorderedThreadPoolEventExecutor(10,
                new DefaultThreadFactory("business"));
        // 为什么不用NioEventLoopGroup线程池来处理业务逻辑?因为只会返回 1 个线程，无法使用多线程来处理
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(0,
                new DefaultThreadFactory("business"));

        // 流量整形，限制读写速度为 100M/s
        GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(new NioEventLoopGroup(),
                100 * 1024 * 1024,100 * 1024 * 1024);

        // 添加黑名单
        IpSubnetFilterRule ipSubnetFilterRule = new IpSubnetFilterRule("127.1.0.1", 16, IpFilterRuleType.REJECT);
        RuleBasedIpFilter ruleBasedIpFilter = new RuleBasedIpFilter(ipSubnetFilterRule);

        AuthHandler authHandler = new AuthHandler();

        SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate();
        System.out.println(selfSignedCertificate.certificate());

        SslContext sslContext = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).build();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .group(boss, worker)
                    // 关闭 nagle 算法
                    .childOption(NioChannelOption.TCP_NODELAY, true)
                    // 最大等待连接数量，默认 128
                    .option(NioChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // debug 出原始数据
                            pipeline.addLast(new LoggingHandler(LogLevel.DEBUG));

                            // 添加黑名单过滤
                            pipeline.addLast("ipFilter",ruleBasedIpFilter);

                            // 流量整形，让应用更加平滑
                            pipeline.addLast("TShandler",globalTrafficShapingHandler);

                            // idle 监测
                            pipeline.addLast("idleCheck",new ServerIdleCheckHandler());

                            // ssl 加密认证
                            SslHandler sslHandler = sslContext.newHandler(ch.alloc());
                            pipeline.addLast("ssl", sslHandler);


                            pipeline.addLast("FrameDecoder", new OrderFrameDecoder());
                            pipeline.addLast(new OrderFrameEncoder());

                            pipeline.addLast(new OrderProtocolEncoder());
                            pipeline.addLast(new OrderProtocolDecoder());

                            // 自定义授权
                            pipeline.addLast("authHandler", authHandler);

                            // 可视化监控
                            pipeline.addLast(eventExecutors,"metricsHandler", metricHandler);
                            pipeline.addLast(new LoggingHandler(LogLevel.INFO));

                            // 增强写，减少 flush 的次数，提升吞吐量，每读 5 次写一次，牺牲了即时性
                            pipeline.addLast("flushEnhance",
                                    new FlushConsolidationHandler(5, true));

                            pipeline.addLast(eventExecutors, new OrderServerProcessHandler());
                        }
                    });

            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();

            channelFuture.channel().closeFuture().get();

        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }


    }

}
